#include "TcpServer.h"
#include "log/Log.h"

#include <iostream>

namespace net
{

TcpServer::TcpServer(EventLoop::ptr ptrEventLoop, IPAddress::ptr ptrAddr)
    : m_mainReactor(ptrEventLoop)
{
    m_ptrAcceptor = std::make_shared<Acceptor>(ptrEventLoop, ptrAddr);
}

TcpServer::~TcpServer()
{
}

void TcpServer::start()
{
    size_t nSize = std::thread::hardware_concurrency();
    m_ptrThreads = std::make_shared<ThreadPool>(nSize);
    for (int i = 0; i < nSize; i++)
    {
        EventLoop::ptr eventLoop = std::make_shared<EventLoop>();
        m_vecSubReactor.push_back(eventLoop);
        m_ptrThreads->put(std::bind(&EventLoop::loop, eventLoop));
    }

    m_ptrAcceptor->setNewConnectionCB(std::bind(&TcpServer::onNewConnection, this, std::placeholders::_1));
    m_ptrAcceptor->startAccept();
}

void TcpServer::onNewConnection(Socket::ptr clientSock)
{
    SYS_FMT_INFO("new client %s connected.", clientSock->getPeerAddress()->getIpPort().c_str()); 
    int index = clientSock->getSocket() % m_vecSubReactor.size();
    Connection::ptr ptrCon = std::make_shared<Connection>(m_vecSubReactor[index], clientSock);
    ptrCon->setHandleEventCB(std::bind(&TcpServer::handleEvent, this, std::placeholders::_1));
    ptrCon->setDeleteConnectionCB(std::bind(&TcpServer::onDeleteConnection, this, std::placeholders::_1));
    m_mapFd2Connection.insert(std::make_pair(clientSock->getSocket(), ptrCon));
}

void TcpServer::onDeleteConnection(Socket::ptr clientSock)
{
    SYS_FMT_INFO("client %s disconnect.", clientSock->getPeerAddress()->getIpPort().c_str()); 
    auto itr = m_mapFd2Connection.find(clientSock->getSocket());
    if (itr != m_mapFd2Connection.end())
    {
        m_mapFd2Connection.erase(itr);
    }
}


void TcpServer::handleEvent(Connection::ptr ptrCon)
{
    std::string str;
    ptrCon->read(str);
    SYS_FMT_INFO("recv from %s msg: %s", ptrCon->getPeerAddress()->getIpPort().c_str(), str.c_str());

    std::cin >> str;
    ptrCon->write(str);
    SYS_FMT_INFO("send to %s msg: %s", ptrCon->getPeerAddress()->getIpPort().c_str(), str.c_str());
}

} // namespace net